package com.tang.provider.netty;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.tang.provider.domain.Request;
import com.tang.provider.domain.Response;
import com.tang.provider.netty.codec.json.ProtocolMessage;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Method;
import java.util.Map;

/**
 * @author Tang
 * @classname NettyServerHandler
 * @description [ TODO ]
 * @date 2021/1/19 23:09
 */
@Slf4j
@ChannelHandler.Sharable
public class NettyServerHandler extends ChannelInboundHandlerAdapter {

    private final Map<String, Object> serviceMap;

    public NettyServerHandler(Map<String, Object> serviceMap) {
        this.serviceMap = serviceMap;
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        log.info("客户端连接成功!" + ctx.channel().remoteAddress());
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        log.info("客户端断开连接!" + ctx.channel().remoteAddress());
        ctx.channel().close();
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        if (msg instanceof ProtocolMessage) {
            ProtocolMessage message = (ProtocolMessage) msg;
            String jsonStr = new String(message.getMessage());
            // 转换成 Request
            Request request = JSONObject.parseObject(jsonStr, Request.class);
            // 心跳方法
            if ("heartBeat".equals(request.getMethodName())) {
                log.info("客户端心跳信息..." + ctx.channel().remoteAddress());
            }else {
                log.info("rpc客户端请求接口:【" + request.getClassName() + "】方法名:【" + request.getMethodName() + "】");
                // 创建一个响应对象
                Response response = new Response();
                response.setRequestId(request.getId());
                try {
                    // 反射执行目标方法
                    Object result = this.handler(request);
                    response.setData(result);
                } catch (Exception e) {
                    response.setCode(1);
                    response.setErrorMsg(e.getMessage());
                    log.error("RPC Server handler request error");
                }
                String jsonString = JSON.toJSONString(response);
                message.setMessage(jsonString.getBytes());
                message.setLen(message.getMessage().length);
                // 写回客户端
                ctx.writeAndFlush(message);
            }
        }
    }

    private Object handler(Request request) throws Exception{
        String className = request.getClassName();
        // 获取对应的服务实例类
        Object serverBean = serviceMap.get(className);
        if (serverBean != null) {
            // 类信息
            Class<?> serverBeanClass = serverBean.getClass();
            // 方法名
            String methodName = request.getMethodName();
            // 参数类型列表
            Class<?>[] parameterTypes = request.getParameterTypes();
            // 参数列表
            Object[] parameters = request.getParameters();
            // 获取本地要执行的方法
            Method method = serverBeanClass.getDeclaredMethod(methodName, parameterTypes);
            // 方法可见
            method.setAccessible(true);
            // 开始执行
            return method.invoke(serverBean, getParameters(parameters,parameterTypes));
        }
        throw new Exception("未找到接口的实现类!,请检查配置信息。");
    }

    private Object[] getParameters(Object[] parameters, Class<?>[] parameterTypes) {
        if (parameters == null || parameterTypes == null) {
            return parameters;
        }
        for (int i = 0; i< parameters.length; i++) {
            parameters[i] = JSONObject.parseObject(parameters[i].toString(), parameterTypes[0]);
        }
        return parameters;
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {

    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent idleStateEvent = (IdleStateEvent) evt;
            String eventType = "";
            switch (idleStateEvent.state()) {
                case ALL_IDLE:
                    eventType = "读写空闲";
                    break;
                case WRITER_IDLE:
                    eventType = "读空闲";
                    break;
                case READER_IDLE:
                    eventType = "读空闲";
                    break;
                default:
                    break;
            }
            System.out.println("【客户端:" + ctx.channel().remoteAddress() + "】:" + eventType);
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ctx.channel().close();
        cause.printStackTrace();
    }
}